﻿using System.Linq.Expressions;
using Hvam.SharePoint.Search.Language;
using Hvam.SharePoint.Search.Language.Parsers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using KeywordQueryParser = Hvam.SharePoint.Search.Language.Parsers.KeywordQueryParser;

namespace Hvam.SharePoint.Search.Tests.Internal.Language.Parsers
{
    [TestClass]
    public class KeywordQueryParserTests
    {
        [TestMethod]
        public void KeywordQueryParserPropertyNameParse()
        {
            // Arrange
            const string input = "property";

            // Act
            var result = KeywordQueryParser.PropertyName.Parse(input);

            // Assert
            Assert.AreEqual(input, result);
        }

        [TestMethod]
        public void KeywordQueryParserPropertyOperatorParse()
        {
            // Arrange
            const string input = "=";

            // Act

            var result = KeywordQueryParser.PropertyOperator.Parse(input);

            // Assert
            Assert.AreEqual(ExpressionType.Equal, result);
        }

        [TestMethod]
        public void KeywordQueryParserPropertyRestrictionParse()
        {
            // Arrange
            const string input = "property=value";

            // Act

            var result = KeywordQueryParser.PropertyRestriction.Parse(input);

            // Assert
            AssertExpression.AreEqual(
                Expression.Equal(
                    KeywordQueryExpression.Property("property"),
                    Expression.Constant("value")), result);
        }

        [TestMethod]
        public void KeywordQueryParserPropertyRestrictionQuoteParse()
        {
            // Arrange
            const string input = "property=\"1 2 3\"";

            // Act
            var result = KeywordQueryParser.PropertyRestriction.Parse(input);

            // Assert
            AssertExpression.AreEqual(
                Expression.Equal(
                    KeywordQueryExpression.Property("property"),
                    Expression.Constant("1 2 3")), result);
        }

        [TestMethod]
        public void KeywordQueryParserPropertyRestrictionSiteContentType()
        {
            // Arrange
            const string input = "Site:http://sharepoint/site contenttype:Item";

            // Act
            var result = KeywordQueryParser.Parse(input);

            // Assert
            AssertExpression.AreEqual(
                Expression.And(
                    KeywordQueryExpression.Contains(
                        KeywordQueryExpression.Property("Site"),
                        Expression.Constant("http://sharepoint/site")),
                    KeywordQueryExpression.Contains(
                        KeywordQueryExpression.Property("contenttype"),
                        Expression.Constant("Item"))
                    ),
                result);
        }

        [TestMethod]
        public void KeywordQueryParserPropertyRestrictionTaxId()
        {
            // Arrange
            const string input = "owstaxIdItemType=#052263385-1fc3-4323-8d6b-50c8f6c3c45d";

            // Act
            var result = KeywordQueryParser.Parse(input);

            // Assert
            AssertExpression.AreEqual(
                Expression.Equal(
                    KeywordQueryExpression.Property("owstaxIdItemType"),
                    Expression.Constant("#052263385-1fc3-4323-8d6b-50c8f6c3c45d")),
                result);
        }

        [TestMethod]
        public void KeywordQueryParserParsePropertyContains()
        {
            // Arrange
            const string input = "title:abc";

            // Act
            var result = KeywordQueryParser.Parse(input);

            // Assert
            AssertExpression.AreEqual(
                KeywordQueryExpression.Contains(
                    KeywordQueryExpression.Property("title"),
                    Expression.Constant("abc")),
                result);
        }

        [TestMethod]
        public void KeywordQueryParserEqualUnderscore()
        {
            // Arrange
            const string input = "title=\"_\"";

            // Act
            var result = KeywordQueryParser.Parse(input);

            // Assert
            AssertExpression.AreEqual(
                Expression.Equal(
                    KeywordQueryExpression.Property("title"),
                    Expression.Constant("_")),
                result);
        }

        [TestMethod]
        public void KeywordQueryParserParse()
        {
            // Arrange
            var tests =
                new TestCases<string, Expression>
                    {
                        new TestCase<string, Expression>
                            {
                                Data =  "property=value",
                                Expected = 
                                    Expression.Equal(
                                        KeywordQueryExpression.Property("property"), 
                                        Expression.Constant("value"))
                            },
                        new TestCase<string, Expression>
                            {
                                Data =  "(property=value)",
                                Expected = 
                                    Expression.Equal(
                                        KeywordQueryExpression.Property("property"), 
                                        Expression.Constant("value"))
                            },
                        new TestCase<string, Expression>
                            {
                                Data =  "((property=value))",
                                Expected = 
                                    Expression.Equal(
                                        KeywordQueryExpression.Property("property"), 
                                        Expression.Constant("value"))
                            },
                        new TestCase<string, Expression>
                            {
                                Data =  "property2=value2",
                                Expected = 
                                    Expression.Equal(
                                        KeywordQueryExpression.Property("property2"), 
                                        Expression.Constant("value2"))
                            },
                        new TestCase<string, Expression>
                            {
                                Data =  "id=1",
                                Expected = 
                                    Expression.Equal(
                                        KeywordQueryExpression.Property("id"), 
                                        Expression.Constant("1"))
                            },
                        new TestCase<string, Expression>
                            {
                                Data =  "id>1",
                                Expected = 
                                    Expression.GreaterThan(
                                        KeywordQueryExpression.Property("id"), 
                                        Expression.Constant("1"))
                            },
                        new TestCase<string, Expression>
                            {
                                Data =  "id<1",
                                Expected = 
                                    Expression.LessThan(
                                        KeywordQueryExpression.Property("id"), 
                                        Expression.Constant("1"))
                            },
                        new TestCase<string, Expression>
                            {
                                Data =  "id>=1",
                                Expected = 
                                    Expression.GreaterThanOrEqual(
                                        KeywordQueryExpression.Property("id"), 
                                        Expression.Constant("1"))
                            },
                        new TestCase<string, Expression>
                            {
                                Data =  "id<=1",
                                Expected = 
                                    Expression.LessThanOrEqual(
                                        KeywordQueryExpression.Property("id"), 
                                        Expression.Constant("1"))
                            },
                        new TestCase<string, Expression>
                            {
                                Data =  "id<>1",
                                Expected = 
                                    Expression.NotEqual(
                                        KeywordQueryExpression.Property("id"), 
                                        Expression.Constant("1"))
                            },
                        new TestCase<string, Expression>
                            {
                                Data =  "id=1 OR property=value",
                                Expected = 
                                    Expression.Or(
                                        Expression.Equal(
                                            KeywordQueryExpression.Property("id"), 
                                            Expression.Constant("1")), 
                                        Expression.Equal(
                                            KeywordQueryExpression.Property("property"), 
                                            Expression.Constant("value"))
                                            )
                            },
                        new TestCase<string, Expression>
                            {
                                Data =  "(id=1 AND (property=value))",
                                Expected = 
                                    Expression.And(
                                        Expression.Equal(
                                            KeywordQueryExpression.Property("id"), 
                                            Expression.Constant("1")), 
                                        Expression.Equal(
                                            KeywordQueryExpression.Property("property"), 
                                            Expression.Constant("value"))
                                            )
                            },
                        new TestCase<string, Expression>
                            {
                                Data =  "id=1 AND id=2 AND id=3",
                                Expected = 
                                    Expression.And(
                                        Expression.Equal(
                                            KeywordQueryExpression.Property("id"), 
                                            Expression.Constant("1")), 
                                            Expression.And(
                                                Expression.Equal(
                                                    KeywordQueryExpression.Property("id"), 
                                                    Expression.Constant("2")), 
                                            Expression.Equal(
                                                KeywordQueryExpression.Property("id"), 
                                                Expression.Constant("3"))
                                            ))
                            },
                        new TestCase<string, Expression>
                            {
                                Data =  "title:abc",
                                Expected = 
                                    KeywordQueryExpression.Contains(
                                        KeywordQueryExpression.Property("title"), 
                                        Expression.Constant("abc"))
                            },
                        new TestCase<string, Expression>
                            {
                                Data =  "site:http://sharepoint/sites/sitesearch/ReusableContent/",
                                Expected = 
                                    KeywordQueryExpression.Contains(
                                        KeywordQueryExpression.Property("site"), 
                                        Expression.Constant("http://sharepoint/sites/sitesearch/ReusableContent/"))
                            },
                        new TestCase<string, Expression>
                            {
                                Data =  "title:title id=1",
                                Expected = 
                                    Expression.And(
                                        KeywordQueryExpression.Contains(
                                            KeywordQueryExpression.Property("title"), 
                                            Expression.Constant("title")), 
                                        Expression.Equal(
                                            KeywordQueryExpression.Property("id"), 
                                            Expression.Constant("1")))
                            },
                    };

            // Act
            tests.Act(KeywordQueryParser.Parse);

            // Assert
            tests.Assert(AssertExpression.AreEqual);
        }

        [TestMethod]
        public void KeywordQueryParserParseDateTime()
        {
            // Arrange
            var tests =
                new TestCases<string, Expression>
                    {
                        new TestCase<string, Expression>
                            {
                                Data =  "date>=\"2012-05-05 16:00:00\"",
                                Expected = 
                                    Expression.GreaterThanOrEqual(
                                        KeywordQueryExpression.Property("date"), 
                                        Expression.Constant("2012-05-05 16:00:00"))
                            },
                        new TestCase<string, Expression>
                            {
                                Data =  "date<=\"2012-05-05 16:00:00Z\"",
                                Expected = 
                                    Expression.LessThanOrEqual(
                                        KeywordQueryExpression.Property("date"), 
                                        Expression.Constant("2012-05-05 16:00:00Z"))
                            },
                        new TestCase<string, Expression>
                            {
                                Data =  "date>2012-05-05",
                                Expected = 
                                    Expression.GreaterThan(
                                        KeywordQueryExpression.Property("date"), 
                                        Expression.Constant("2012-05-05"))
                            },
                            new TestCase<string, Expression>
                            {
                                Data =  "date=2012-05-05",
                                Expected = 
                                    Expression.Equal(
                                        KeywordQueryExpression.Property("date"), 
                                        Expression.Constant("2012-05-05"))
                            },
                    };

            // Act
            tests.Act(KeywordQueryParser.Parse);

            // Assert
            tests.Assert(AssertExpression.AreEqual);
        }
    }
}
